<template>
	<div class="component-upload-image">
		<template v-if="video">
			<div v-for="(item, index) in state.fileList" :key="index + ''" class="el-upload-list__item">
				<video :src="item.url" width="148" height="148" controls preload="preload" />
				<div class="el-upload-list__item-actions">
					<el-icon :size="20" color="#FFFFFF" @click="onLookVideo(index)" style="margin-left: 10px">
						<ele-ZoomIn />
					</el-icon>
					<el-icon :size="20" color="#FFFFFF" v-if="!isDelete" @click="onRemoveVideo(index)" style="margin-left: 10px">
						<ele-Delete />
					</el-icon>
				</div>
			</div>
		</template>
		<el-upload
			action="#"
			:multiple="Number(limit) == 1 ? false : true"
			:on-preview="onPreviewUpload"
			:on-remove="onRemoveUpload"
			:on-error="onErrorUpload"
			:on-change="onChangeUpload"
			:on-exceed="onExceedUpload"
			:before-upload="onBeforeUpload"
			:file-list="state.fileList"
			:show-file-list="!video"
			list-type="picture-card"
			:http-request="onHttpRequestUpload"
			:limit="limit"
			:class="{ fileComputed, isDelete }"
			ref="imageUploadRef"
		>
			<el-icon>
				<ele-UploadFilled />
			</el-icon>
			<template #tip v-if="isShowTip">
				<el-alert
					:title="`上传文件支持 ${fileType.join(' / ')} 格式，单张文件大小不超过 ${fileSize}MB${
						imageSize ? '，建议文件尺寸为 ' + imageSize : ''
					}，且文件数量不超过 ${limit} 张`"
					type="info"
					show-icon
					:closable="false"
					style="line-height: 16px; margin-top: 5px"
				/>
			</template>
		</el-upload>
		<el-dialog v-if="video" v-model="state.dialogVisible" title="预览" width="800px" append-to-body>
			<video :src="state.videoUrl" style="display: block; max-width: 100%; margin: 0 auto" controls preload="preload" />
		</el-dialog>
		<el-image-viewer
			v-if="!video && state.dialogVisible"
			:initial-index="state.lookNum"
			@close="state.dialogVisible = false"
			:url-list="fileUrlList"
		/>
	</div>
</template>

<script setup lang="ts" name="imageUploadCOS">
import { ElLoading, ElMessage } from 'element-plus';
import { computed, inject, reactive, ref, watch } from 'vue';
import upload from '/@/utils/uploadCos';
import { randomString } from '/@/utils/utils';

const Dayjs: any = inject('dayjs');

// 定义父组件传过来的值
const props = defineProps({
	path: {
		type: String,
		default: () => 'material',
	},
	modelValue: {
		type: String,
		default: () => '',
	},
	// 文件数量限制
	limit: {
		type: Number,
		default: () => 1,
	},
	// 文件类型, 例如['png', 'jpg', 'jpeg']
	fileType: {
		type: Array,
		default: () => ['png', 'jpg', 'jpeg', 'webp', 'bmp'],
	},
	// 大小限制(MB)
	fileSize: {
		type: Number,
		default: () => 1,
	},
	imageSize: {
		type: String,
		default: () => '',
	},
	video: {
		type: Boolean,
		default: () => false,
	},
	disabled: {
		type: Boolean,
		default: () => false,
	},
	isDelete: {
		type: Boolean,
		default: () => false,
	},
	isMaterial: {
		type: Boolean,
		default: () => false,
	},
	isDialogUpload: {
		type: Boolean,
		default: () => false,
	},
	// 是否显示提示
	isShowTip: {
		type: Boolean,
		default: true,
	},
});

// 定义子组件向父组件传值/事件
const emit = defineEmits(['update:modelValue']);
const state = reactive({
	fileList: [] as any,
	dialogVisible: false,
	lookValue: '',
	lookNum: 0,
	videoUrl: '',
});
const uploadLoading = ref();
const imageUploadRef = ref();

// 设定一个计算属性 判断是否已经超过上传上限
const fileComputed = computed(() => {
	return state.fileList.length >= props.limit;
});
const fileUrlList = computed(() => {
	return state.fileList.map((item: any) => item.url);
});

watch(
	() => props.modelValue,
	(val) => {
		if (val) {
			if (state.fileList.length) {
				return;
			}

			// 首先将值转为数组
			const list = Array.isArray(val) ? val : props.modelValue.split(',');
			// 然后将数组转为对象数组
			state.fileList = list.map((item, index) => {
				return { uid: item.uid || new Date().getTime() + index + 1, name: item, url: item, upload: true };
			});
		} else {
			state.fileList = [];
			return [];
		}
	},
	{
		deep: true,
		immediate: true,
	}
);

watch(
	() => props.isDialogUpload,
	() => {
		console.log('啊啊啊');
		state.fileList = []
	}
);

/********** 点击事件(on开头) **********/
// 视频预览
const onLookVideo = (num: number) => {
	state.dialogVisible = true;
	state.lookNum = num;
	state.videoUrl = state.fileList[num].url;
};
// 视频删除
const onRemoveVideo = (num: number) => {
	state.fileList = state.fileList.filter((item: any, index: number) => index !== num);
	emit('update:modelValue', state.fileList.map((item: any) => item.url).join(','));
};
// 文件预览
const onPreviewUpload = (file: any) => {
	state.dialogVisible = true;
	state.lookNum = state.fileList.findIndex((item: any) => item.url == file.url);
};
// 删除文件
const onRemoveUpload = () => {
	emit('update:modelValue', state.fileList.length ? listToString(state.fileList) : '');
};
// 上传成功
const onChangeUpload = (file: any, fileList: any) => {
	console.log('选择文件', file, fileList);
	if (fileList) {
		state.fileList = fileList.map((item: any) => item);
	}
};
// 上传失败
const onErrorUpload = () => {
	uploadLoading.value.close();
};
// 上传前校验
const onBeforeUpload = (file: any) => {
	let isImg = false;
	if (props.fileType.length) {
		let fileExtension = '';
		if (file.name.lastIndexOf('.') > -1) {
			fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1);
		}
		isImg = props.fileType.some((type: any) => {
			if (file.type.indexOf(type) > -1) return true;
			if (fileExtension && fileExtension.indexOf(type) > -1) return true;
			return false;
		});
	} else {
		isImg = file.type.indexOf('image') > -1;
	}

	if (!isImg) {
		ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式!`);
		return false;
	}
	if (props.fileSize) {
		const isLt = file.size / 1024 / 1024 < props.fileSize;
		if (!isLt) {
			ElMessage.error(`上传文件大小不能超过 ${props.fileSize} MB!`);
			return false;
		}
	}
	uploadLoading.value = ElLoading.service({
		lock: true,
		text: '正在上传文件，请稍候...',
		spinner: 'el-icon-loading',
		background: 'rgba(0, 0, 0, 0.7)',
	});
};

// 自定义上传
const onHttpRequestUpload = (res: any) => {
	let fileExtension = res.file.name.substring(res.file.name.lastIndexOf('.') + 1);
	let path = `/${props.path}/${Dayjs().year()}/${Dayjs().month()}/${Dayjs().date()}/${randomString(32).toLowerCase()}.${fileExtension}`;
	if (props.isMaterial) {
		path = `/${props.path}/${res.file.name}`;
	}
	upload(res.file, path)
		.then((res1: any) => {
			if (res1.err) {
				console.log('失败', res1);

				ElMessage.error(res1.err.message);
				const fileFindIndex = state.fileList.findIndex((item: any) => item.uid == 1);
				state.fileList.splice(fileFindIndex, 1);
				uploadLoading.value.close();
				imageUploadRef.value.handleRemove(res.file);
				return;
			}
			console.log('成功', res1);
			state.fileList = state.fileList.map((item: any) => {
				if (item.uid == res.file.uid) {
					return { url: res1.url, upload: true, uid: item.uid }; // 将本地的地址换成腾讯云地址
				}
				return item;
			});
			emit('update:modelValue', listToString(state.fileList));
			uploadLoading.value.close();
		})
		.catch(() => {
			imageUploadRef.value.handleRemove(res.file);
			uploadLoading.value?.close();
			emit('update:modelValue', state.fileList.map((item: any) => item.url).join(','));
		});
};

const onExceedUpload = (files: any, uploadFiles: any) => {
	ElMessage.warning(`当前限制选择 ${props.limit} 张文件，本次选择了 ${files.length} 张文件，共选择了 ${files.length + uploadFiles.length} 张文件`);
};
// 对象转成指定字符串分隔
const listToString = (list: Array<any>, separator: string = ',') => {
	let strs = '';
	for (let i in list) {
		if (list[i].url) {
			strs += list[i].url + separator;
		}
	}
	return strs != '' ? strs.substring(0, strs.length - 1) : '';
};
</script>

<style lang="scss" scoped>
.component-upload-image {
	.el-upload-list__item {
		position: relative;
		width: 148px;
		height: 148px;
		border: 1px solid #c0ccda;
		border-radius: 6px;

		video {
			border-radius: 6px;
		}

		.el-upload-list__item-actions {
			position: absolute;
			width: 100%;
			height: 100%;
			left: 0;
			top: 0;
			cursor: default;
			display: inline-flex;
			justify-content: center;
			align-items: center;
			background-color: rgba(0, 0, 0, 0.5);
			border-radius: 6px;
			transition: opacity 0.3;
			opacity: 0;
		}

		&:hover {
			.el-upload-list__item-actions {
				opacity: 1;
			}
		}
	}
}
</style>

<style lang="scss">
.component-upload-image {
	.fileComputed {
		.el-upload--picture-card {
			display: none;
		}
	}

	.isDelete {
		.el-upload-list {
			.el-upload-list__item {
				.el-upload-list__item-delete {
					display: none;
				}
			}
		}

		.el-upload--picture-card {
			display: none;
		}
	}

	.isVideo {
		display: none;
	}
}
</style>
